package ar.edu.itba.it.pdc.httpParser;

import java.util.LinkedList;
import java.util.List;

import ar.edu.itba.it.pdc.httpParser.exceptions.HttpBadRequestException;
import ar.edu.itba.it.pdc.httpParser.exceptions.HttpMethodNotSuportedException;
import ar.edu.itba.it.pdc.httpParser.exceptions.HttpVersionNotSuportedException;
import ar.edu.itba.it.pdc.httpParser.interfaces.Parser;
import ar.edu.itba.it.pdc.httpParser.models.HttpRequestLine;
import ar.edu.itba.it.pdc.httpParser.models.HttpVersion;
import ar.edu.itba.it.pdc.httpParser.models.Method;
import ar.edu.itba.it.pdc.httpParser.models.Token;
import ar.edu.itba.it.pdc.httpParser.models.TokenType;

public class RequestLineParser implements Parser {
	private enum State {
		METHOD, METHODEND, RESOURCE, PROTOCOL, PROTOCOLEND, VERSION, VERSIONEND
	};

	private State state = State.METHOD;
	
	private List<Token> resource = new LinkedList<Token>();

	private HttpRequestLine model = new HttpRequestLine();

	public int parseToken(Token token)
			throws HttpMethodNotSuportedException, HttpBadRequestException,
			HttpVersionNotSuportedException {
		switch (state) {
		case METHOD:

			if (token.isType(TokenType.WORD)) {
				if (token.is("POST")) {
					model.setMethod(Method.POST);
					state = State.METHODEND;
				} else if (token.is("GET")) {
					model.setMethod(Method.GET);
					state = State.METHODEND;
				} else if (token.is("HEAD")) {
					model.setMethod(Method.HEAD);
					state = State.METHODEND;
				} else {
					throw new HttpMethodNotSuportedException(token);
				}
			} else {
				throw new HttpBadRequestException(token);
			}
			break;

		case RESOURCE:
			if (token.isType(TokenType.WORD) || token.isType(TokenType.DIVIDE)
					|| token.isType(TokenType.DOTS)) {
				resource.add(token);
			} else if (token.isType(TokenType.SPACE)) {
				model.setResource(resource);
				state = State.PROTOCOL;
			} else {
				throw new HttpBadRequestException(token);
			}
			break;

		case PROTOCOL:
			if (token.isType(TokenType.WORD) && token.is("HTTP")) {
				state = State.PROTOCOLEND;
			} else {
				throw new HttpBadRequestException(token);
			}
			break;

		case VERSION:
			if (token.isType(TokenType.WORD)) {
				if (token.is("1.0")) {
					model.setVersion(HttpVersion.ONE);
					state = State.VERSIONEND;
				} else if (token.is("1.1")) {
					model.setVersion(HttpVersion.ONEDOTONE);
					state = State.VERSIONEND;
				} else {
					throw new HttpVersionNotSuportedException();
				}
			} else {
				throw new HttpBadRequestException(token);
			}
			break;

		case METHODEND:
			if (token.isType(TokenType.SPACE)) {
				state = State.values()[state.ordinal() + 1];
			} else {
				throw new HttpBadRequestException(token);
			}
			break;

		case PROTOCOLEND:
			if (token.isType(TokenType.DIVIDE)) {
				state = State.values()[state.ordinal() + 1];
			} else {
				throw new HttpBadRequestException(token);
			}
			break;

		case VERSIONEND:
			if (token.isType(TokenType.CRLF)) {
				return 0;
			} else {
				throw new HttpBadRequestException(token);
			}
		}
		return -1;
	}
	
	public HttpRequestLine getModel(){
		return model;
	}
}
